#include "Base.h"

// Ecrit un message sur la socket (sans argumants).
int Base::ecrireMessage(int idMessage)
{
    cout<<"ecrireMessage(int).\n";
    return ecrireEntierUnOctet(idMessage);
}

// Ecrit une massage sur la socket avec en argumant un entier.
int Base::ecrireMessage(int idMessage, int param1)
{
    cout<<"ecrireMessage(int, int).\n";
    int retour = ecrireEntierUnOctet(idMessage);
    ecrireEntier(param1);
    return retour;
}

// Ecrit un message sur la socket avec en argument un char*.
int Base::ecrireMessage(int idMessage, const char *param1)
{
    cout<<"ecrireMessage(int, char*).\n";
    int retour = ecrireEntierUnOctet(idMessage);
    ecrireChaine(param1);
    return retour;
}

// Ecrit un message sur la socket avec en argument une string.
int Base::ecrireMessage(int idMessage, const string& param1)
{
    cout<<"ecrireMessage(int, string).\n";
    int retour = ecrireEntierUnOctet(idMessage);
    ecrireChaine(param1);
    return retour;
}

// Ecrit un message sur la socket avec en argumant une ListeChaines*.
int Base::ecrireMessage(int idMessage, ListeChaines *param1) // deprecated
{
    cout<<"ecrireMessage(int, liste).\n";
    int retour = ecrireEntierUnOctet(idMessage);

    ecrireListeChaines(param1);
    return retour;
}

int Base::ecrireMessage(int idMessage, const list<string>& param1)
{
    cout<<"ecrireMessage(int, list<string>).\n";
    int retour = ecrireEntierUnOctet(idMessage);

    ecrireListeChaines(param1);
    return retour;
}

int Base::ecrireMessage(int idMessage, const char *param1, ListeChaines *param2) // deprecated
{
    cout<<"ecrireMessage(int, char*, liste).\n";
    int retour = ecrireEntierUnOctet(idMessage);
    ecrireChaine(param1);
    ecrireListeChaines(param2);
    return retour;
}

int Base::ecrireMessage(int idMessage, const string& param1, ListeChaines *param2) // deprecated
{
    cout<<"ecrireMessage(int, string, liste).\n";
    int retour = ecrireEntierUnOctet(idMessage);
    ecrireChaine(param1);
    ecrireListeChaines(param2);
    return retour;
}

int Base::ecrireMessage(int idMessage, const char* param1, const list<string>& param2) // deprecated
{
    cout<<"ecrireMessage(int, char*, list<string>).\n";
    int retour = ecrireEntierUnOctet(idMessage);
    ecrireChaine(param1);
    ecrireListeChaines(param2);
    return retour;
}

int Base::ecrireMessage(int idMessage, const string& param1, const list<string>& param2)
{
    cout<<"ecrireMessage(int, string, list<string>).\n";
    int retour = ecrireEntierUnOctet(idMessage);
    ecrireChaine(param1);
    ecrireListeChaines(param2);
    return retour;
}

int Base::ecrireMessage(int idMessage, const string& param1, const string& param2)
{
    cout<<"ecrireMessage(int, string, string).\n";
    int retour = ecrireEntierUnOctet(idMessage);
    ecrireChaine(param1);
    ecrireChaine(param2);
    return retour;
}

int Base::ecrireMessage(int idMessage, const string &param1, const string &param2, const string &param3)
{
    cout<<"ecrireMessage(int, string, list<string>).\n";
    int retour = ecrireEntierUnOctet(idMessage);
    ecrireChaine(param1);
    ecrireChaine(param2);
    ecrireChaine(param3);
    return retour;
}

int Base::ecrireMessage(int idMessage, const string& param1, const string& param2, const list<string>& param3)
{
    cout<<"ecrireMessage(int, string, list<string>).\n";
    int retour = ecrireEntierUnOctet(idMessage);
    ecrireChaine(param1);
    ecrireChaine(param2);
    ecrireListeChaines(param3);
    return retour;
}

// Private

/* Lit un entier sur la socket. */
int Base::lireEntierUnOctet() // lit un entier.
{
    cout<<"LireEntier.\n";
    int value = -1;
    int nbOctetsALire = 4;
    int nbOctetsLu = 0;
    do
    {
        int nb = read(sock, &value+nbOctetsLu, nbOctetsALire-nbOctetsLu);
        if(nb == 0) return 0; // si la socket est fermée.
        if(nb != -1) nbOctetsLu+=nb;// si il n'y a rien a lire sur la socket.
    }
    while(nbOctetsALire!=nbOctetsLu);
    value = ntohl(value);
    cout<<value<<endl;
    return value;
}

/* Lit un entier sur la socket. */
int Base::lireEntier() // lit un entier.
{
    cout<<"LireEntier.\n";
    int value = -1;
    int nbOctetsALire = 4;
    int nbOctetsLu = 0;
    do
    {
        int nb = read(sock, &value+nbOctetsLu, nbOctetsALire-nbOctetsLu);
        if(nb == 0) return 0; // si la socket est fermée.
        if(nb != -1) nbOctetsLu+=nb;// si il n'y a rien a lire sur la socket.
    }
    while(nbOctetsALire!=nbOctetsLu);
    value = ntohl(value);
    cout<<value<<endl;
    return value;
}

/* Lit une chaine de caractères sur la socket. */
string Base::lireChaine() // lit une chaine de caractères.
{
    cout<<"LireChaine.\n";
    char *value = 0;
    int nbOctetsALire = 0;
    int nbOctetsLu = 0;
    nbOctetsALire = lireEntier(); // On récupère le nombre d'octets à lire.
    value = new char[nbOctetsALire + 1];
    value[nbOctetsALire] = 0;
    do
    {
        nbOctetsLu+= read(sock, value+nbOctetsLu, nbOctetsALire-nbOctetsLu);
    }
    while(nbOctetsALire!=nbOctetsLu);
    string valueString = value;

    return valueString;
}

/* Lit une liste de chaines de caractères sur la socket. */
list<string> Base::lireListeChaines()
{
    cout<<"LireListeChaines.\n";
    int nbChaines = 0;
    nbChaines = lireEntier();
    //cout<<"nombre de chaines: "<<nbChaines<<'\n';
    list<string> value;
    for(int i = 0; i < nbChaines; ++i)
    {
        value.push_back(lireChaine());
        cout<<value.back()<<"\n";
    }

    return value;
}

/* Ecrit un entier de un octet sur la socket. */
int Base::ecrireEntierUnOctet(int entier)
{
    cout<<"EcrireEntierUnOctet.\n";
    cout<<entier<<endl;
    int value = htonl(entier);
    return write(sock, &value, 4);
}

/* Ecrit un entier sur la socket. */
int Base::ecrireEntier(int entier)
{
    cout<<"EcrireEntier.\n";
    cout<<entier<<endl;
    int value = htonl(entier);
    return write(sock, &value, 4);
}

/* Ecrit une chaine de caractères sur la socket. */
int Base::ecrireChaine(const char* chaine)
{
    cout<<"EcrireChaine(char*).\n";
    int nbChar = strlen(chaine);
    ecrireEntier(nbChar); // On ecrit le nombre de carateres de la chaine.
    return write(sock, chaine, nbChar); // On écrit la chaine de caracteres.
}

/* Ecrit une chaine de caractères sur la socket. */
int Base::ecrireChaine(const string& chaine)
{
    cout<<"EcrireChaine(string).\n";
    int nbChar = chaine.size();
    ecrireEntier(nbChar); // On ecrit le nombre de carateres de la chaine.
    return write(sock, chaine.c_str(), nbChar); // On écrit la chaine de caracteres.
}

/* Ecrit une liste de chaines de caractères sur la socket. */
int Base::ecrireListeChaines(ListeChaines *listeChaines)
{
    cout<<"EcrireListeChaines(liste).\n";
    int retour = ecrireEntier(listeChaines->nbChaines); // On écrit le nombre de chaines à envoyer.
    for(int i = 0; i < listeChaines->nbChaines; ++i) // On écrit toutes les chaines.
    {
        ecrireChaine(listeChaines->listeChaines[i]);
    }
    return retour;
}

int Base::ecrireListeChaines(const list<string>& listeChaines)
{
    cout<<"EcrireListeChaines(list<string>).\n";
    int retour = ecrireEntier(listeChaines.size()); // On écrit le nombre de chaines à envoyer.
    list<string> listeChainesTMP = listeChaines;
    list<string>::iterator it = listeChainesTMP.begin();
    while(it != listeChainesTMP.end()) // On écrit toutes les chaines.
    {
        ecrireChaine(*it);
        ++it;
    }
    return retour;
}
